/***********************************************************************************
 * 文件名： mcu_flash.c
 * 作者： 刘言
 * 版本： 1
 * 说明：
 * 		HC32 的 Flash 驱动，擦写逻辑、时序的实现，提供页擦写API。
 * 修改记录：
 * 	2021/11/22: 初版。 刘言。
***********************************************************************************/

#include "mcu_flash.h"
#include "HC32_LyLib.h"

/**
 ******************************************************************************
 ** \brief FLASH 编程时间参数配置
 **
 ** FLASH编程时间参数配置数组定义 (4MHz)
 ******************************************************************************/
const uint32_t TIMING_4M[] = {
                                    0x20u,          //Tnvs
                                    0x17u,          //Tpgs
                                    0x1Bu,          //Tprog
                                    0x4650u,        //Tserase
                                    0x222E0u,       //Tmerase
                                    0x18u,          //Tprcv
                                    0xF0u,          //Tsrcv
                                    0x3E8u          //Tmrcv
                                  };


IN_LINE static void Bypass()
{
    M0P_FLASH->BYPASS = 0X5A5A;
    M0P_FLASH->BYPASS = 0XA5A5;
}

IN_LINE static void Unlock()
{
    while(M0P_FLASH->SLOCK!=FLASH_UNLOCK_VALUE)
    {
        Bypass();
        M0P_FLASH->SLOCK = FLASH_UNLOCK_VALUE;
    }
}

// 给FLASH上锁，禁止擦写
IN_LINE static void Lock()
{
    while(M0P_FLASH->SLOCK != 0)
    {
        Bypass();
        M0P_FLASH->SLOCK = 0;
    }
}


void Flash_Init()
{
    u8 i;
    vu32 *pFlashRegs;
    pFlashRegs = (vu32 *)M0P_FLASH_BASE;
    for(i=0; i<8; i++)
    {
        while(pFlashRegs[i] != TIMING_4M[i]*FLASH_CLK/4)
        {
            Bypass();
            pFlashRegs[i] = TIMING_4M[i]*FLASH_CLK/4;
        }
    }
}

#define WRITE_BYTE_PER_TIMES    1       // 1,4 一次写入的字节数


void Flash_WritePage(u32 addr, const u8 *buff)
{
    u16 i;
#if (WRITE_BYTE_PER_TIMES == 1)
    u8 * pflash;
    pflash = (u8 *)addr;  // 转换成指向Flash的指针,便于寻址
#elif (WRITE_BYTE_PER_TIMES ==4)
    u32 * pflash;
    u32 * pram;
    pflash = (u32 *)addr;  // 转换成指向Flash的指针,便于寻址
    pram = (u32 *)buff;
#endif

    while(M0P_FLASH->CR_f.BUSY);

    Unlock();

    // 擦除页
    while(M0P_FLASH->CR_f.OP!=2)
    {
        Bypass();
        M0P_FLASH->CR_f.OP=2; // 页擦除操作
    }
    *pflash = 0xFF;   // 触发擦除
    while(M0P_FLASH->CR_f.BUSY);    // 等待操作完成

    // 写数据
    while(M0P_FLASH->CR_f.OP!=1)
    {
        Bypass();
        M0P_FLASH->CR_f.OP=1; // 写入操作
    }
#if (WRITE_BYTE_PER_TIMES == 1)
    for(i=0; i<FLASH_PAGE_SIZE; i++)    // 按字节写入数据
    {
        pflash[i] = buff[i];
        while(M0P_FLASH->CR_f.BUSY);    // 等待操作完成
    }
#elif (WRITE_BYTE_PER_TIMES == 4)
    for(i=0; i<(FLASH_PAGE_SIZE/4); i++)    // 按WORD(4bytes)写入数据
    {
        pflash[i] = pram[i];
        while(M0P_FLASH->CR_f.BUSY);    // 等待操作完成
    }
#endif
    Lock();
}






